using Pdf2epub.BusinessLogic;
using Pdf2epub.UI;
using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;

namespace Pdf2epub.Model
{
    public enum ImageProcessing
    {
        None,
        ShrinkToMaxSize
    }

    public class ProjectConfiguration : BaseObject // INotifyPropertyChanged
    {
        private readonly FontAssignmentDataCollection m_HtmlReplacements = new FontAssignmentDataCollection();

        private string m_Author;
        private double m_AverageLineDistance;

        private string m_CoverImagePath;
        private bool m_DetectTables = true;
        private float m_EndHeight;

        private PageRangeCollection m_ExcludedPages;
        private bool m_FirstImageElementIsCoverImage;
        private HtmlReplacementCollection m_HtmlReplacementCollection;
        private int m_IgnoreImagesSmallThanPixel;
        private ImageProcessing m_ImageProcessing = ImageProcessing.ShrinkToMaxSize;
        private double m_IndentDistance;
        private string m_Language = "en";
        private float m_MaxFontSize;

        private int m_MaxImageSize = 800;
        private double m_MaximumLineDistance;

        private double m_MaxoffsetForLine = 5;
        private int m_MinCoverImageSize = 800;
        private float m_MinFontSize;

        private double m_MinimumLineDistance;

        private double m_MinTableCellSize = 20;
        private double m_MostlyUsedLineDistance;

        private int m_NumberOfPages;
        private int m_PageToRenderEnd;
        private int m_PageToRenderStart;
        private int m_ParagraphDistance;

        private string m_PdfPath;
        private float m_StartHeight;

        private double m_TabeDetectedCellFuzzyness = 1;
        private double m_TableDetectedMinRowDistance = 10;
        private double m_TableDetectionAllowedBaselineOffset = 0.01;
        private TextReplacementCollection m_TextReplacements = new TextReplacementCollection();
        private string m_Title;

        [Category("Document")]
        [DisplayName("Author")]
        public string Author
        {
            get { return m_Author; }
            set
            {
                m_Author = value;
                OnPropertyChanged("Author");
            }
        }

        [Category("PDF Document Statistics")]
        [DisplayName("Average Line Distance")]
        [ReadOnly(true)]
        public double AverageLineDistance
        {
            get { return m_AverageLineDistance; }
            set
            {
                m_AverageLineDistance = value;
                OnPropertyChanged("AverageLineDistance");
            }
        }

        //[ReadOnly(true)]
        [Category("Document")]
        [DisplayName("Detected cover image path")]
        [Editor(typeof(ImageFileEditor), typeof(ImageFileEditor))]
        public string CoverImagePath
        {
            get { return m_CoverImagePath; }
            set
            {
                m_CoverImagePath = value;
                OnPropertyChanged("CoverImagePath");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Detect tables")]
        public bool DetectTables
        {
            get { return m_DetectTables; }
            set
            {
                m_DetectTables = value;
                OnPropertyChanged("DetectTables");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Detection Area Y Pos End")]
        public float EndHeight
        {
            get { return m_EndHeight; }
            set
            {
                m_EndHeight = value;
                OnPropertyChanged("EndHeight");
            }
        }

        [Category("Processing")]
        [DisplayName("Pages to exclude in final book")]
        public PageRangeCollection ExcludedPages
        {
            get { return m_ExcludedPages; }
            set
            {
                m_ExcludedPages = value;
                OnPropertyChanged("ExcludedPages");
            }
        }

        [Category("Document")]
        [DisplayName("First image on page one is cover")]
        public bool FirstImageElementIsCoverImage
        {
            get { return m_FirstImageElementIsCoverImage; }
            set
            {
                m_FirstImageElementIsCoverImage = value;
                OnPropertyChanged("FirstImageElementIsCoverImage");
            }
        }

        [Category("Processing")]
        [Browsable(false)]
        public FontAssignmentDataCollection FontAssignmentDataCollection
        {
            get { return m_HtmlReplacements; }
        }

        [ReadOnly(true)]
        [Category("Document")]
        [DisplayName("Html Output Path")]
        [XmlIgnore]
        public string HtmlOutputPath
        {
            get
            {
                string baseDir = Path.GetDirectoryName(PdfPath);
                string fileName = Path.GetFileNameWithoutExtension(PdfPath);
                return string.Format(@"{0}\html_{1}", baseDir, fileName);
            }
        }

        [Browsable(false)]
        public HtmlReplacementCollection HtmlReplacements
        {
            get
            {
                if (m_HtmlReplacementCollection == null)
                {
                    m_HtmlReplacementCollection = new HtmlReplacementCollection();
                }
                if (m_HtmlReplacementCollection.Count == 0)
                {
                    foreach (var defaultReplacement in HtmlReplacement.DefaultReplacements)
                    {
                        m_HtmlReplacementCollection.Add(defaultReplacement);
                    }
                }
                return m_HtmlReplacementCollection;
            }
            set
            {
                m_HtmlReplacementCollection = value;
                OnPropertyChanged("HtmlReplacementCollection");
            }
        }

        [Category("Processing")]
        [DisplayName("Minimum image size to be included (0=all)")]
        public int IgnoreImagesSmallThanPixel
        {
            get { return m_IgnoreImagesSmallThanPixel; }
            set
            {
                m_IgnoreImagesSmallThanPixel = value;
                OnPropertyChanged("IgnoreImagesSmallThanPixel");
            }
        }

        [ReadOnly(true)]
        [Category("Document")]
        [DisplayName("Html Output Path")]
        [XmlIgnore]
        public string ImageOutputPath
        {
            get
            {
                string baseDir = Path.GetDirectoryName(PdfPath);
                string fileName = Path.GetFileNameWithoutExtension(PdfPath);
                return string.Format(@"{0}\html_{1}\{2}", baseDir, fileName, Controler.ImageOutputSubPath);
            }
        }

        [Category("Processing")]
        [DisplayName("Image Processing")]
        public ImageProcessing ImageProcessing
        {
            get { return m_ImageProcessing; }
            set
            {
                m_ImageProcessing = value;
                OnPropertyChanged("ImageProcessing");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Indent Distance (x)")]
        public double IndentDistance
        {
            get { return m_IndentDistance; }
            set
            {
                m_IndentDistance = value;
                OnPropertyChanged("Title");
            }
        }

        [Category("Document")]
        [DisplayName("Language")]
        public string Language
        {
            get { return m_Language; }
            set
            {
                m_Language = value;
                OnPropertyChanged("Language");
            }
        }

        [Category("Fonts to detect")]
        [DisplayName("Maximum Font Size")]
        public float MaxFontSize
        {
            get { return m_MaxFontSize; }
            set
            {
                m_MaxFontSize = value;
                OnPropertyChanged("MaxFontSize");
            }
        }

        [Category("Processing")]
        [DisplayName("Maximum Image Size")]
        public int MaxImageSize
        {
            get { return m_MaxImageSize; }
            set
            {
                m_MaxImageSize = value;
                OnPropertyChanged("MaxImageSize");
            }
        }

        [Category("PDF Document Statistics")]
        [DisplayName("Maximum Line Distance")]
        [ReadOnly(true)]
        public double MaximumLineDistance
        {
            get { return m_MaximumLineDistance; }
            set
            {
                m_MaximumLineDistance = value;
                OnPropertyChanged("MaximumLineDistance");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Minimum table cell width")]
        public double MaxOffsetForLine
        {
            get { return m_MaxoffsetForLine; }
            set
            {
                m_MaxoffsetForLine = value;
                OnPropertyChanged("MaxOffsetForLine");
            }
        }

        [Category("Document")]
        [DisplayName("Minimum CoverImage Size")]
        public int MinCoverImageSize
        {
            get { return m_MinCoverImageSize; }
            set
            {
                m_MinCoverImageSize = value;
                OnPropertyChanged("MinCoverImageSize");
            }
        }

        [Category("Fonts to detect")]
        [DisplayName("Minimum Font Size")]
        public float MinFontSize
        {
            get { return m_MinFontSize; }
            set
            {
                m_MinFontSize = value;
                OnPropertyChanged("MinFontSize");
            }
        }

        [Category("PDF Document Statistics")]
        [DisplayName("Minimum Line Distance")]
        [ReadOnly(true)]
        public double MinimumLineDistance
        {
            get { return m_MinimumLineDistance; }
            set
            {
                m_MinimumLineDistance = value;
                OnPropertyChanged("MinimumLineDistance");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Minimum table cell width")]
        public double MinTableCellSize
        {
            get { return m_MinTableCellSize; }
            set
            {
                m_MinTableCellSize = value;
                OnPropertyChanged("MinTableCellSize");
            }
        }

        [Category("PDF Document Statistics")]
        [DisplayName("Mostly Used Line Distance")]
        [ReadOnly(true)]
        public double MostlyUsedLineDistance
        {
            get { return m_MostlyUsedLineDistance; }
            set
            {
                m_MostlyUsedLineDistance = value;
                OnPropertyChanged("MostlyUsedLineDistance");
            }
        }

        [ReadOnly(true)]
        [Category("Document")]
        [DisplayName("Number of pages")]
        public int NumberOfPages
        {
            get { return m_NumberOfPages; }
            set
            {
                m_NumberOfPages = value;
                OnPropertyChanged("NumberOfPages");

                if (PageToRenderEnd == 0)
                {
                    PageToRenderEnd = NumberOfPages;
                }

                if (PageToRenderStart == 0)
                {
                    PageToRenderStart = 1;
                }
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Page rendering (end)")]
        public int PageToRenderEnd
        {
            get { return m_PageToRenderEnd; }
            set
            {
                m_PageToRenderEnd = value;
                if ((m_PageToRenderEnd > m_NumberOfPages) && (m_NumberOfPages != 0))
                {
                    m_PageToRenderEnd = m_NumberOfPages;
                }
                if ((m_PageToRenderEnd < PageToRenderStart) && (PageToRenderStart != 0))
                {
                    m_PageToRenderEnd = PageToRenderStart;
                }
                OnPropertyChanged("PageToRenderEnd");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Page rendering (start)")]
        public int PageToRenderStart
        {
            get { return m_PageToRenderStart; }
            set
            {
                m_PageToRenderStart = value;
                if (m_PageToRenderStart < 1)
                {
                    m_PageToRenderStart = 1;
                }
                if (m_PageToRenderStart > m_PageToRenderEnd)
                {
                    PageToRenderEnd = PageToRenderStart;
                }
                OnPropertyChanged("PageToRenderStart");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Paragraph Distance")]
        public int ParagraphDistance
        {
            get { return m_ParagraphDistance; }
            set
            {
                m_ParagraphDistance = value;
                OnPropertyChanged("ParagraphDistance");
            }
        }

        [ReadOnly(true)]
        [Category("Document")]
        [DisplayName("PDF Path")]
        public string PdfPath
        {
            get { return m_PdfPath; }
            set
            {
                m_PdfPath = value;
                OnPropertyChanged("PdfPath");
                OnPropertyChanged("ImageOutputPath");
                OnPropertyChanged("HtmlOutputPath");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Detection Area Y Pos Start")]
        public float StartHeight
        {
            get { return m_StartHeight; }
            set
            {
                m_StartHeight = value;
                OnPropertyChanged("StartHeight");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Table Detection Allowed Cell Fuzzyness")]
        public double TabeDetectedCellFuzzyness
        {
            get { return m_TabeDetectedCellFuzzyness; }
            set
            {
                m_TabeDetectedCellFuzzyness = value;
                OnPropertyChanged("TabeDetectedCellFuzzyness");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Table Detection Minimum Row Distance")]
        public double TableDetectedMinRowDistance
        {
            get { return m_TableDetectedMinRowDistance; }
            set
            {
                m_TableDetectedMinRowDistance = value;
                OnPropertyChanged("TableDetectedMinRowDistance");
            }
        }

        [Category("PDF Document Outline & Detection")]
        [DisplayName("Table Detection Allowed Baseline Offset")]
        public double TableDetectionAllowedBaselineOffset
        {
            get { return m_TableDetectionAllowedBaselineOffset; }
            set
            {
                m_TableDetectionAllowedBaselineOffset = value;
                OnPropertyChanged("TableDetectionAllowedBaselineOffset");
            }
        }

        [Browsable(false)]
        public TextReplacementCollection TextReplacements
        {
            get { return m_TextReplacements; }
            set
            {
                m_TextReplacements = value;
                OnPropertyChanged("TextReplacements");
            }
        }

        [Category("Document")]
        [DisplayName("Title")]
        public string Title
        {
            get { return m_Title; }
            set
            {
                m_Title = value;
                OnPropertyChanged("Title");
            }
        }

        public static ProjectConfiguration LoadFromFile(string path)
        {
            using (TextReader textReader = new StreamReader(path))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(ProjectConfiguration));
                ProjectConfiguration projectConfiguration = serializer.Deserialize(textReader) as ProjectConfiguration;
                textReader.Close();

                return projectConfiguration;
            }
        }

        public void WriteToFile(string path)
        {
            using (TextWriter textWriter = new StreamWriter(path, false))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(ProjectConfiguration));
                serializer.Serialize(textWriter, this);
                textWriter.Flush();
                textWriter.Close();
            }
        }
    }
}